﻿using System;
using System.Runtime.Serialization;
using System.Text;

namespace Kyoh.Lib.Win32API.NetResources
{
    /// <summary>ネットワーク接続において発生したエラーを定義する例外。</summary>
	[Serializable]
	public class WNetException : Exception
	{
        /// <summary><see cref="WNetException"/> クラスの新しいインスタンスを初期化します。</summary>
		[CLSCompliant(false)]
		public WNetException(string message, WNetConnectionResult errorCode) : base(message) { this.ErrorCode = errorCode; }
        
        /// <summary><see cref="WNetException"/> クラスの新しいインスタンスを初期化します。</summary>
        [CLSCompliant(false)]
		public WNetException(string message, Exception inner, WNetConnectionResult errorCode) : base(message, inner) { this.ErrorCode = errorCode; }
        
        /// <summary><see cref="WNetException"/> クラスの新しいインスタンスを初期化します。</summary>
        protected WNetException(SerializationInfo info, StreamingContext context) : base(info, context) { }

        /// <summary>ネットワーク接続において発生したエラーコードを取得します。</summary>
		[CLSCompliant(false)]
		public WNetConnectionResult ErrorCode
		{
			get { return base.Data.Contains("ErrorCode") ? (WNetConnectionResult)base.Data["ErrorCode"] : 0; }
			private set
			{
				if (base.Data.Contains("ErrorCode"))
					base.Data["ErrorCode"] = value;
				else
					base.Data.Add("ErrorCode", value);
			}
		}

        /// <summary>ネットワーク接続に関連するエラーコードを判定して、必要であれば <see cref="WNetException"/> 例外を発生させます。</summary>
        /// <param name="result">ネットワーク接続に関連するエラーコードを表す <see cref="WNetConnectionResult"/> 列挙型の値を指定します。</param>
		internal static void ThrowException(WNetConnectionResult result)
		{
			switch (result)
			{
				case WNetConnectionResult.NoError:
					return;
				case WNetConnectionResult.AccessDenied:
					throw new WNetException("ネットワークリソースへのアクセスが拒否されました。", result);
				case WNetConnectionResult.AlreadyAssigned:
					throw new WNetException("localName で指定したローカルデバイスは既にネットワークリソースに接続されています。", result);
				case WNetConnectionResult.BadDevType:
					throw new WNetException("ローカルデバイスの種類とネットワークリソースの種類が一致しません。", result);
				case WNetConnectionResult.BadDevice:
					throw new WNetException("localName で指定した値が無効です。", result);
				case WNetConnectionResult.BadNetName:
					throw new WNetException("remoteName で指定した値を、どのネットワークリソースのプロバイダも受け付けません。リソースの名前が無効か、指定した名前のリソースが見つかりません。", result);
				case WNetConnectionResult.BadProfile:
					throw new WNetException("ユーザープロファイルの形式が正しくありません。", result);
				case WNetConnectionResult.BadProvider:
					throw new WNetException("provider で指定した値がどのプロバイダとも一致しません。", result);
				case WNetConnectionResult.Busy:
					throw new WNetException("ルーターまたはプロバイダがビジー（ おそらく初期化中）です。この関数をもう一度呼び出してください。", result);
				case WNetConnectionResult.Cancelled:
					throw new WNetException("ネットワークリソースのプロバイダのいずれかでユーザーがダイアログボックスを使って接続操作を取り消したか、接続先のリソースが接続操作を取り消しました。", result);
				case WNetConnectionResult.CannotOpenProfile:
					throw new WNetException("恒久的な接続を処理するためのユーザープロファイルを開くことができません。", result);
				case WNetConnectionResult.ConnectionUnavail:
					throw new WNetException("装置は現在接続されていませんが、恒久的な接続として記憶されています。詳細については、解説を参照してください。", result);
				case WNetConnectionResult.DeviceAlreadyRemembered:
					throw new WNetException("localName で指定したデバイスのエントリは既にユーザープロファイル内に存在します。", result);
				case WNetConnectionResult.DeviceInUse:
					throw new WNetException("指定したデバイスがアクティブなプロセスによって使用中のため、切断できません。", result);
				case WNetConnectionResult.Extended:
					uint error = (uint)result;
					var errorMessage = new StringBuilder();
					var errorName = new StringBuilder();
					if (NativeMethods.WNetGetLastError(ref error, errorMessage, uint.MaxValue, errorName, uint.MaxValue) == WNetConnectionResult.NoError)
						throw new WNetException("ネットワーク固有のエラーが発生しました。[" + errorName.ToString() + " (" + error + error + ")] " + errorMessage.ToString(), result);
					else
						throw new WNetException("ネットワーク固有のエラーが発生しました。", result);
				case WNetConnectionResult.InvalidHandle:
					throw new WNetException("hEnum パラメータが指定したハンドルが有効ではありません。", result);
				case WNetConnectionResult.InvalidParameter:
					throw new WNetException("scope パラメータまたは type パラメータの値が無効です。あるいは、パラメータの値の組み合わせが無効です。", result);
				case WNetConnectionResult.InvalidPassword:
					throw new WNetException("指定したパスワードが無効です。", result);
				case WNetConnectionResult.MoreData:
					throw new WNetException("バッファのサイズが不十分です。length パラメータが指す変数に、必要なバッファサイズが格納されています。この関数で取得可能なエントリが残っています。", result);
				case WNetConnectionResult.NoNetOrBadPath:
					throw new WNetException("ネットワークコンポーネントが開始されていないか、指定した名前が利用できないために、操作を行えませんでした。", result);
				case WNetConnectionResult.NoNetwork:
					throw new WNetException("ネットワークに接続されていません。", result);
				case WNetConnectionResult.NotConnected:
					throw new WNetException("name パラメータで指定した名前がリダイレクトされているデバイスを表していないか、name で指定したデバイスにシステムが接続していません。", result);
				case WNetConnectionResult.NotContainer:
					throw new WNetException("netResource パラメータがコンテナリソースを指していません。", result);
				case WNetConnectionResult.OpenFiles:
					throw new WNetException("開いているファイルがあり、force が false です。", result);
				case WNetConnectionResult.LoginFailure:
					throw new WNetException("ログインに失敗しました。ユーザ名かパスワードが間違っています。", result);
				default:
					throw new WNetException("WindowsNetwork: 不明なエラー", result);
			}
		} 


	}
}
